package com.leeson.portal.core.service;

/*
 * 0-1 ver Ver字段是协议的版本号，长度为 1 字节，Ver = 0x02或01
 * 2-3 type Type字段定义报文的类型，长度为 1 字节
 * 4-5 pap/chap 01/00 Pap/Chap字段定义此用户的认证方式，长度为 1 字节，只对Type值为 0x03 的认证请求报文有意义
 * 6-7 00 Rsv目前为保留字段，长度为 1 字节，在所有报文中值为0 
 * 8-11 Serial NoSerialNo字段为报文的序列号，长度为 2字节，由PortalServer随机生成,Portal Server必须尽量保证不同认证流程的SerialNo在一定时间内不得重复，在同一个认证流程中所有报文的SerialNo相同
 * 12-15 ReqID ReqID字段长度为 2 个字节，由BAS设备随机生成，尽量使得在一定时间内ReqID不重复。
 * 16-23 UserIP	UserIP字段为Portal用户的IP地址，长度为 4 字节，其值由PortalServer根据其获得的IP地址填写
 * 24-27 UserPort UserPort字段目前没有用到，长度为 2 字节，在所有报文中其值为0
 * 28-29 ErrCode  长度为 1字节
 *                	(1)、对于Type值为1、3、7的报文，ErrCode字段无意义，其值为0；
 *				  	(2)、当Type值为 2 时：
 *					ErrCode＝0，表示BAS设备告诉PortalServer请求Challenge成功；
 *					ErrCode＝1，表示BAS设备告诉PortalServer请求Challenge被拒绝； 
 *					ErrCode＝2，表示BAS设备告诉PortalServer此链接已建立；
 *					ErrCode＝3，表示BAS设备告诉PortalServer有一个用户正在认证过程中，请稍后再试；
 *					ErrCode＝4，则表示BAS设备告诉PortalServer此用户请求Challenge失败（发生错误）；
 *					(3)、当Type值为 4 时：
 *					ErrCode＝0，表示BAS设备告诉PortalServer此用户认证成功；
 *					ErrCode＝1，表示BAS设备告诉PortalServer此用户认证请求被拒绝；
 *					ErrCode＝2，表示BAS设备告诉PortalServer此链接已建立； 
 *					ErrCode＝3，表示BAS设备告诉PortalServer有一个用户正在认证过程中，请稍后再试；
 * 					ErrCode＝4 ，表示BAS设备告诉PortalServer此用户认证失败（发生错误）；
 *					(4)、当Type值为 5 时：
 *					ErrCode＝0，表示此报文是PortalServer发给BAS设备的请求下线报文；
 *					ErrCode＝1，表示此报文是在PortalServer没有收到BAS设备发来的对各种请求的响应报文，而定时器时间到（即超时）时由PortalServer发给BAS设备的报文；
 *					(5)、当Type值为 6 时：
 *					ErrCode＝0，表示BAS设备告诉PortalServer此用户下线成功；
 * 					ErrCode＝1，表示BAS设备告诉PortalServer此用户下线被拒绝；
 * 					ErrCode＝2,  表示BAS设备告诉PortalServer此用户下线失败（发生错误）；
 * 30-31 AttrNum 属性个数
 */

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.context.ApplicationContext;

import com.leeson.portal.core.model.Config;
import com.leeson.portal.core.model.OnlineMap;
import com.leeson.portal.core.service.utils.PortalUtil;
import com.leeson.portal.core.utils.SpringContextHelper;
import com.leeson.portal.manage.domain.Account;
import com.leeson.portal.manage.domain.LinkRecord;
import com.leeson.portal.manage.domain.LogRecord;
import com.leeson.portal.manage.service.AccountService;
import com.leeson.portal.manage.service.LinkRecordService;
import com.leeson.portal.manage.service.LogRecordService;


public class ReportServer extends Thread {
	private static Config config = Config.getInstance();
	private static OnlineMap onlineMap=OnlineMap.getInstance();
	private static Logger log = Logger.getLogger(ReportServer.class);
	
//	ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
	ApplicationContext ac =SpringContextHelper.getApplicationContext();
	
	
	DatagramPacket data = null;

	public ReportServer(DatagramPacket data) {

		this.data = data;
	}

	public void run() {

		if(config.getDebug().equals("1")){
			log.info("收到的数据包大小：" + data.getLength());
		}
		
		byte[] Req_Data_Base = new byte[data.getLength()]; // 构建接收基础包大小100
		for (int l = 0; l < Req_Data_Base.length; l++) {
			Req_Data_Base[l] = data.getData()[l];
		}

		// 获取客户端的ip和端口号
		String ip = data.getAddress().getHostAddress();
		int port = data.getPort();
		// 构建portal协议中的字段包
		byte[] Ver = new byte[1];
		byte[] Type = new byte[1];
		byte[] Mod = new byte[1];
		byte[] Rsvd = new byte[1];
		byte[] SerialNo = new byte[2];
		byte[] ReqID = new byte[2];
		byte[] UserIP = new byte[4];
		byte[] UserPort = new byte[2];
		byte[] ErrCode = new byte[1];
		byte[] AttrNum = new byte[1];

		// 给各字段包赋初始值为接收到的包的值
		Ver[0] = Req_Data_Base[0];
		Type[0] = Req_Data_Base[1];
		Mod[0] = Req_Data_Base[2];
		Rsvd[0] = Req_Data_Base[3];
		SerialNo[0] = Req_Data_Base[4];
		SerialNo[1] = Req_Data_Base[5];
		ReqID[0] = Req_Data_Base[6];
		ReqID[1] = Req_Data_Base[7];
		UserIP[0] = Req_Data_Base[8];
		UserIP[1] = Req_Data_Base[9];
		UserIP[2] = Req_Data_Base[10];
		UserIP[3] = Req_Data_Base[11];
		UserPort[0] = Req_Data_Base[12];
		UserPort[1] = Req_Data_Base[13];
		ErrCode[0] = Req_Data_Base[14];
		AttrNum[0] = Req_Data_Base[15];

		if(config.getDebug().equals("1")){
			log.info("收到BAS: " + ip + ":" + port + ":" + "发来的主动报文："
					+ PortalUtil.Getbyte2HexString(Req_Data_Base));
		}
		
		//主动下线报文
		if ((int) (Type[0] & 0xFF) == 8) {
			String userIP=bytesToIp(UserIP);
			
			if(onlineMap.getOnlineUserMap().containsKey(userIP)){
				String[] loginInfo=onlineMap.getOnlineUserMap().get(userIP);
				String username=loginInfo[0];
				
				if(config.getAuth_interface().equals("1")){
					doLinkRecord(loginInfo);
				}
				
				onlineMap.getOnlineUserMap().remove(userIP);
				
				if(config.getDebug().equals("1")){
					doLogRecord("IP:"+userIP+",用户:"+username+",被设备或者Radius踢下线！");
				}
				if(config.getDebug().equals("1")){
					log.info("用户IP: " + userIP + " 用户名: " +username+ " 被设备或者Radius踢下线！");
				}
			}
			
		}
		
		
		
	}
	
	
	/**
     * 字节数组转化为IP
     * @param bytes
     * @return string 
     */
    public static String bytesToIp(byte[] bytes) {
        return new StringBuffer().append(bytes[0] & 0xFF).append('.').append(
                bytes[1] & 0xFF).append('.').append(bytes[2] & 0xFF)
                .append('.').append(bytes[3] & 0xFF).toString();
    }
    
	/**
	 * 连接日志
	 * @param request
	 * @param ip
	 * @param username
	 */
	private void doLinkRecord(String loginInfo[]) {
		Long userId=Long.parseLong(loginInfo[1]);
		Long recordId=Long.parseLong(loginInfo[2]);
		LinkRecordService linkRecordService=(LinkRecordService) ac.getBean("linkRecordServiceImpl");
		AccountService accountService=(AccountService) ac.getBean("accountServiceImpl");
		LinkRecord linkRecord=linkRecordService.getById(recordId);
		Account account=accountService.getById(userId);
		String state=account.getState();
		
		Date now=new Date();
		linkRecord.setEndDate(now);
		Long costTime=now.getTime()-linkRecord.getStartDate().getTime();
		linkRecord.setTime(costTime);
		linkRecordService.update(linkRecord);
		
		if(config.getAuth_interface().equals("1")){
			if(state.equals(String.valueOf(3))||state.equals(String.valueOf(2))){
				Long haveTime=account.getTime();
				Long newHaveTime=haveTime-costTime;
				if(state.equals(String.valueOf(2))){
					if(newHaveTime<=0){
						account.setState(String.valueOf(0));
					}
					account.setTime(newHaveTime);
					accountService.update(account);
				}
			}
		}
		
		
	}
	
	
	
	private void doLogRecord(String info) {
		LogRecord logRecord=new LogRecord();
		Date nowDate=new Date();
		logRecord.setInfo(info);
		logRecord.setRec_date(nowDate);
		LogRecordService logRecordService=(LogRecordService) ac.getBean("logRecordServiceImpl");
		logRecordService.save(logRecord);
	}
	
	
    
	

	

	public static void openServer() throws Exception {

		@SuppressWarnings("resource")
		DatagramSocket socket = new DatagramSocket(Integer.parseInt(config.getPortal_port()));
		if(config.getDebug().equals("1")){
			log.info("OpenPortalServer 服务启动成功   监听UDP端口号：50100");
		}
		
		while (true) {
			byte[] b = new byte[100];
			DatagramPacket data = new DatagramPacket(b, b.length);
			socket.receive(data);
			new ReportServer(data).start();
		}
	}

}
